#ifndef __RTRT_RAY_H__
#define __RTRT_RAY_H__

#include "Common.h"
#include "Primitive.h"

namespace RTRT
{
	// lookup table for the modulo operation
	static const unsigned int modulo[] = { 0,1,2,0,1 };

	struct Ray
	{
		Vector3 origin;
		Vector3 direction;
	};

	struct Hit
	{
		float dist;
		int triIndex;
		float u;
		float v;
	};

	// intersection detection with triangles
	inline void Intersect(TriAccel &triAccel, Ray &ray, Hit &hit)
	{
		#define ku modulo[triAccel.k+1]
		#define kv modulo[triAccel.k+2]

		// start high-latency division as early as possible
		const float nd = 1 / (ray.direction.M[triAccel.k] + triAccel.n_u*ray.origin.M[ku] + triAccel.n_v*ray.direction.M[kv]);
		const float f = (triAccel.n_d - ray.origin.M[triAccel.k] - triAccel.n_u * ray.origin.M[ku] - triAccel*ray.origin.M[kv]) * nd;

		// check for the valid distance
		if ( !(hit.dest > f && f > EPSILON_E6) )
			return;
		// compute hit point (hu,hv) positioning on uv plane
		const float hu = ray.origin.M[ku] + f*ray.direction.M[ku];
		const float hv = ray.origin.M[kv] + f*ray.direction.M[kv];

		// check first barycentric coordinate
		const float lambda = (hu*triAccel.b_nu + hv*triAccel.b_nv + triAccel.b_d);
		if (lambda < 0.0f)
			return;

		// check second barycentric coordinate
		const float mue = (hu*triAccel.c_nu + hv*acc.c_nv + triAccel.c_d);
		if (mue < 0.0f)
			return;

		// check third barycentric coordinate
		if (lambda + mue > 1.0f)
			return;

		// have a valid hitpoint here, store it
		hit.dist = f;
		//hit.tri = triNum;
		hit.u = lambda;
		hit.v = mue;
	}

	class Ray
	{
	public:
		Ray(Vector3& origin, Vector3& direction) 
			: m_origin(origin), m_direction(direction) {
			
		}

		// Setters and Getters
		void setOrigin(const Vector3& origin) {
			m_origin = origin;
		}
		
		void setDirection(const Vector3& direction) {
			m_direction = direction;
		}

		Vector3& getOrigin() {
			return m_origin;
		}
		
		Vector3& getDirection() {
			return m_direction;
		}
		
	private:
		/** The origin point of the ray
		*/
		Vector3 m_origin;

		/** The direction of the ray
		*/
		Vector3 m_direction;
	};	
}

#endif
